"""
文件存储 API
"""
import urllib.parse
from typing import List
from fastapi import UploadFile, File, Form, Path, Query, Body, Depends
from fastapi.responses import RedirectResponse, StreamingResponse
import asyncio

from axiom_boot.api.models import success_response, ApiResponse, PaginationParams, PaginatedResponse
from axiom_boot.di import controller, autowired
from axiom_boot.api.controller import (
    BaseController, get, post, delete, put
)
from axiom_boot.core.exceptions import NotFoundException, BusinessException

from src.storage.service.storage_service import StorageService
from src.storage.models.api_models import (
    FileStorageVO, FolderCreateDTO, ItemRenameDTO, ItemsMoveDTO, FolderTreeNodeVO,
    StorageFilterParams
)


@controller("/storage", tags=["文件存储管理"])
class StorageController(BaseController):
    """
    提供文件和文件夹管理的统一接口。
    """

    def __init__(self, storage_service: StorageService = autowired()):
        self.storage_service = storage_service

    @post(
        "/folder", 
        summary="创建文件夹",
        response_model=ApiResponse[FileStorageVO],
    )
    async def create_folder(
        self,
        dto: FolderCreateDTO = Body(...)
    ) -> ApiResponse[FileStorageVO]:
        new_folder = await self.storage_service.create_folder(dto)
        return success_response(
            data=FileStorageVO.model_validate(new_folder),
            message="文件夹创建成功"
        )

    @get(
        "/download/{file_id}", 
        summary="下载文件",
    )
    async def download_file(
        self,
        file_id: str = Path(..., description="文件ID")
    ):
        _file_id = int(file_id)
        file_meta = await self.storage_service.find_by_pk_or_fail(_file_id)
        if file_meta.is_dir or not file_meta.storage_key:
            raise BusinessException("目标不是一个有效的文件")

        if file_meta.provider == "s3":
            download_url = await self.storage_service.fs_service.get_presigned_url(
                path=file_meta.storage_key,
                bucket_name=file_meta.bucket
            )
            return RedirectResponse(url=download_url, status_code=302)
        
        elif file_meta.provider == "local":
            file_stream, mime_type = await self.storage_service.get_local_file_stream(_file_id)
            if not file_stream:
                raise NotFoundException("文件在本地存储中未找到")
            
            encoded_filename = urllib.parse.quote(file_meta.name)
            headers = {
                'Content-Disposition': f"attachment; filename*=UTF-8''{encoded_filename}"
            }
            return StreamingResponse(file_stream, media_type=mime_type, headers=headers)

        raise BusinessException("不支持的文件存储类型，无法下载")

    @get(
        "/tree", 
        summary="获取文件夹树",
        response_model=ApiResponse[List[FolderTreeNodeVO]],
    )
    async def get_folder_tree(
        self,
        filters: StorageFilterParams = Depends()
    ) -> ApiResponse[List[FolderTreeNodeVO]]:
        tree = await self.storage_service.get_folder_tree(filters=filters)
        return success_response(data=tree)

    @get(
        "/list", 
        summary="获取文件夹内容列表",
        response_model=ApiResponse[PaginatedResponse[FileStorageVO]],
    )
    async def list_items(
        self,
        filters: StorageFilterParams = Depends(),
        pagination: PaginationParams = Depends()
    ) -> ApiResponse[PaginatedResponse[FileStorageVO]]:
        paginated_items = await self.storage_service.list_items_in_folder(
            filters=filters,
            pagination=pagination
        )
        return success_response(data=paginated_items)

    @put(
        "/move", 
        summary="移动文件或文件夹",
        response_model=ApiResponse,
    )
    async def move_items(
        self,
        dto: ItemsMoveDTO = Body(...)
    ) -> ApiResponse:
        await self.storage_service.move_items(dto)
        return success_response(message="移动成功")

    @delete(
        "/{item_id}", 
        summary="删除文件或文件夹",
        response_model=ApiResponse,
    )
    async def remove_item(
        self,
        item_id: str = Path(..., description="要删除的文件或文件夹ID"),
    ) -> ApiResponse:
        await self.storage_service.delete_item(int(item_id))
        return success_response(message="删除成功")

    @put(
        "/{item_id}/rename", 
        summary="重命名文件或文件夹",
        response_model=ApiResponse,
    )
    async def rename_item(
        self,
        item_id: str = Path(..., description="文件或文件夹ID"),
        dto: ItemRenameDTO = Body(...)
    ) -> ApiResponse:
        await self.storage_service.rename_item(int(item_id), dto)
        return success_response(message="重命名成功")

    @post(
        "/upload", 
        summary="上传文件(支持多文件)",
        response_model=ApiResponse[List[FileStorageVO]],
    )
    async def upload_file(
        self,
        bucket: str = Form(..., description="目标存储桶名称"),
        parent_id: str = Form(None, description="目标父文件夹ID，不传则为根目录"),
        files: List[UploadFile] = File(..., description="要上传的文件列表"),
    ) -> ApiResponse[List[FileStorageVO]]:
        
        _parent_id = int(parent_id) if parent_id is not None else None

        async def _upload_single_file(file: UploadFile) -> FileStorageVO:
            async def stream_generator(spooled_file):
                while chunk := await spooled_file.read(8192):
                    yield chunk

            file_meta = await self.storage_service.upload_file(
                filename=file.filename,
                mime_type=file.content_type,
                size_bytes=file.size,
                stream=stream_generator(file.file),
                bucket=bucket,
                parent_id=_parent_id,
            )
            return FileStorageVO.model_validate(file_meta)

        upload_tasks = [_upload_single_file(file) for file in files]
        uploaded_files_vo = await asyncio.gather(*upload_tasks)
        
        return success_response(data=uploaded_files_vo, message="文件上传成功")
